// const exports = {};
// eval(`export.default = function(){}`)
// export.default(10,20,30)
/*
function require(file) {
	var exports = {};
	(function (exports, code) {
		eval(code)
	})(exports, 'exports.default = function(a,b){return a + b}')
  return exports
}
var add = require('add.js').default
console.log(add(1 , 2))
*/
/*
(function (list) {
  function require(file) {
    var exports = {};
    (function (exports, code) {
      eval(code);
    })(exports, list[file]);
    return exports;
  }
  require("index.js");
})({
  "index.js": `
    var add = require('add.js').default
    console.log(add(1 , 2))
        `,
  "add.js": `exports.default = function(a,b){return a + b}`,
});
 */
/*
{
  "./src/index.js": {
    "deps": { "./add.js": "./src/add.js" },
    "code": "....."
  },
  "./src/add.js": {
    "deps": {},
    "code": "......"
  }
}
 */
const fs = require('fs');
const path = require('path');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const babel = require('@babel/core');

//1. 解析模块文件信息
function getModuleInfo(file){
  // 读取入口文件内容
  const body = fs.readFileSync(file, "utf8");

  // 解析ast
  const ast = parser.parse(body, {
    sourceType: "module"
  });
  
  // 收集依赖
  const deps = {};
  traverse(ast, {
    ImportDeclaration({node}){
      const dirname = path.dirname(file);
      const depName = node.source.value;
      const abspath = "./" + path.join(dirname, depName);
      deps[depName] = abspath;
    }
  })

  // es6 转 es5
  const { code } = babel.transformFromAst(ast, null, {
    presets: ['@babel/preset-env']
  });

  const moduleInfo = {file, deps, code};

  return moduleInfo;
}


//2. 解析依赖 生成依赖

function parseModules(file){
   const entry = getModuleInfo(file);
   const temp = [entry];
   const depsGraph = {};
   getDeps(temp, entry);
   temp.forEach((moduleInfo) => {
    depsGraph[moduleInfo.file] = {
      deps: moduleInfo.deps,
      code: moduleInfo.code
    }
   })
   return depsGraph;
}


function getDeps(temp, {deps}){
  Object.keys(deps).forEach((key) => {
    const child = getModuleInfo(deps[key]);
    temp.push(child);
    getDeps(temp, child);
  })
}


//3. 生成打包文件

function outputBundle(file){
  const depsGraph = JSON.stringify(parseModules(file));
  return `(function(graph){
    function require(file){
      function absRequire(relPath){
        return require(graph[file].deps[relPath])
      }
      var exports = {};
      (function(require,exports,code){
        eval(code);
      })(absRequire, exports, graph[file].code);
      return exports;
    }
    require('${file}')
  })(${depsGraph})`
}


const bundle = outputBundle("./app/index.js");

fs.writeFileSync('./dist/app.js',bundle);
